package com.ruoyi.campus.service.impl;

import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.campus.domain.PatrolPoint;
import com.ruoyi.campus.domain.Department;
import com.ruoyi.campus.domain.SecurityGuard;
import com.ruoyi.campus.mapper.PatrolPointMapper;
import com.ruoyi.campus.mapper.DepartmentMapper;
import com.ruoyi.campus.mapper.SecurityGuardMapper;
import com.ruoyi.campus.service.IPatrolPointService;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import org.springframework.beans.factory.annotation.Value;

import java.io.*;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.util.Base64;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.ByteArrayOutputStream;

/**
 * 巡查点位信息Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-06-29
 */
@Service
public class PatrolPointServiceImpl implements IPatrolPointService
{
    private static final Logger log = LoggerFactory.getLogger(PatrolPointServiceImpl.class);
    
    @Autowired
    private PatrolPointMapper patrolPointMapper;
    
    @Autowired
    private DepartmentMapper departmentMapper;
    
    @Autowired
    private SecurityGuardMapper securityGuardMapper;
    
    @Value("${ruoyi.profile:/home/ruoyi/uploadPath}")
    private String uploadPath;

    /**
     * 查询巡查点位信息
     * 
     * @param pointId 巡查点位信息主键
     * @return 巡查点位信息
     */
    @Override
    public PatrolPoint selectPatrolPointByPointId(Long pointId)
    {
        return patrolPointMapper.selectPatrolPointByPointId(pointId);
    }

    /**
     * 根据点位唯一编码查询巡查点位信息
     * 
     * @param pointUniqueCode 点位唯一编码
     * @return 巡查点位信息
     */
    @Override
    public PatrolPoint selectPatrolPointByUniqueCode(String pointUniqueCode)
    {
        return patrolPointMapper.selectPatrolPointByUniqueCode(pointUniqueCode);
    }

    /**
     * 查询巡查点位信息列表
     * 
     * @param patrolPoint 巡查点位信息
     * @return 巡查点位信息
     */
    @Override
    public List<PatrolPoint> selectPatrolPointList(PatrolPoint patrolPoint)
    {
        return patrolPointMapper.selectPatrolPointList(patrolPoint);
    }

    /**
     * 新增巡查点位信息
     * 
     * @param patrolPoint 巡查点位信息
     * @return 结果
     */
    @Override
    public int insertPatrolPoint(PatrolPoint patrolPoint, String operName)
    {
        Department dept = null;
        // 校验部门是否存在
        if (patrolPoint.getDeptId() != null)
        {
            dept = departmentMapper.selectDepartmentByDeptId(patrolPoint.getDeptId());
            if (dept == null)
            {
                throw new RuntimeException("所选部门不存在，请重新选择");
            }
            if ("1".equals(dept.getStatus()))
            {
                throw new RuntimeException("所选部门已停用，请重新选择");
            }
        }
        
        // 校验安全员是否存在
        if (patrolPoint.getGuardId() != null)
        {
            SecurityGuard guard = securityGuardMapper.selectSecurityGuardByGuardId(patrolPoint.getGuardId());
            if (guard == null)
            {
                throw new RuntimeException("所选安全员不存在，请重新选择");
            }
        }

        // 生成点位唯一编码
        if (StringUtils.isEmpty(patrolPoint.getPointUniqueCode()))
        {
            String pointUniqueCode = buildPointUniqueCode(patrolPoint, dept);
            if (StringUtils.isNotEmpty(pointUniqueCode))
            {
                patrolPoint.setPointUniqueCode(pointUniqueCode);
            }
        }

        if (!checkPointCodeUnique(patrolPoint.getPointUniqueCode(), null)) {
            throw new RuntimeException("唯一编码已存在，请重新选择");
        }
        
        patrolPoint.setCreateBy(operName);
        patrolPoint.setCreateTime(DateUtils.getNowDate());
        patrolPoint.setBindTime(DateUtils.getNowDate());
        int result = patrolPointMapper.insertPatrolPoint(patrolPoint);
        
        // 如果插入成功，生成二维码
        if (result > 0 && patrolPoint.getPointId() != null)
        {
            try
            {
                // 生成二维码code（使用点位ID）
                String qrCode = String.valueOf(patrolPoint.getPointId());
                patrolPoint.setQrCode(qrCode);
                
                // 生成二维码Base64
                String qrCodeBase64 = generateQRCodeBase64(qrCode);
                if (qrCodeBase64 != null)
                {
                    patrolPoint.setQrCodeBase64(qrCodeBase64);
                }
                
                // 更新点位信息
                patrolPointMapper.updatePatrolPoint(patrolPoint);
                log.info("为点位[{}]生成二维码成功: code={}", patrolPoint.getPointId(), qrCode);
            }
            catch (Exception e)
            {
                log.error("为点位[{}]生成二维码失败: {}", patrolPoint.getPointId(), e.getMessage());
                // 二维码生成失败不影响点位创建
            }
        }
        
        return result;
    }

    /**
     * 修改巡查点位信息
     * 
     * @param patrolPoint 巡查点位信息
     * @return 结果
     */
    @Override
    public int updatePatrolPoint(PatrolPoint patrolPoint, String operName)
    {
        PatrolPoint oldPointInfo = null;
        // 校验点位ID是否存在
        if (patrolPoint.getPointId() != null)
        {
            oldPointInfo = patrolPointMapper.selectPatrolPointByPointId(patrolPoint.getPointId());
            if (oldPointInfo == null)
            {
                log.error("修改巡查点位失败，点位ID[{}]不存在", patrolPoint.getPointId());
                return 0;
            }
        }
        
        Department dept = null;
        // 校验部门是否存在
        if (patrolPoint.getDeptId() != null)
        {
            dept = departmentMapper.selectDepartmentByDeptId(patrolPoint.getDeptId());
            if (dept == null)
            {
                throw new RuntimeException("所选部门不存在，请重新选择");
            }
            if ("1".equals(dept.getStatus()))
            {
                throw new RuntimeException("所选部门已停用，请重新选择");
            }
        }
        
        // 校验安全员是否存在
        if (patrolPoint.getGuardId() != null)
        {
            SecurityGuard guard = securityGuardMapper.selectSecurityGuardByGuardId(patrolPoint.getGuardId());
            if (guard == null)
            {
                throw new RuntimeException("所选安全员不存在，请重新选择");
            } else if (oldPointInfo != null && !guard.getGuardId().equals(oldPointInfo.getGuardId())){
                patrolPoint.setBindTime(DateUtils.getNowDate());
            }
        }
        
        // 重新生成点位唯一编码（当相关字段发生变化时）
        String newPointUniqueCode = buildPointUniqueCode(patrolPoint, dept);
        if (StringUtils.isNotEmpty(newPointUniqueCode))
        {
            patrolPoint.setPointUniqueCode(newPointUniqueCode);
        }
        
        patrolPoint.setUpdateBy(operName);
        patrolPoint.setUpdateTime(DateUtils.getNowDate());
        return patrolPointMapper.updatePatrolPoint(patrolPoint);
    }

    /**
     * 批量删除巡查点位信息
     * 
     * @param pointIds 需要删除的巡查点位信息主键
     * @return 结果
     */
    @Override
    public int deletePatrolPointByPointIds(String pointIds)
    {
        return patrolPointMapper.deletePatrolPointByPointIds(Convert.toStrArray(pointIds));
    }

    /**
     * 删除巡查点位信息
     * 
     * @param pointId 巡查点位信息主键
     * @return 结果
     */
    @Override
    public int deletePatrolPointByPointId(Long pointId)
    {
        return patrolPointMapper.deletePatrolPointByPointId(pointId);
    }
    
    /**
     * 解绑巡查点位的安全员
     * 
     * @param pointId 巡查点位ID
     * @param updateBy 更新人
     * @return 结果
     */
    @Override
    public int unbindGuardFromPoint(Long pointId, String updateBy)
    {
        return patrolPointMapper.unbindGuardFromPoint(pointId, updateBy);
    }
    
    /**
     * 校验点位编码唯一性
     * 
     * @param pointUniqueCode 点位唯一编码
     * @param pointId 点位ID（修改时传入，新增时为null）
     * @return 结果
     */
    @Override
    public boolean checkPointCodeUnique(String pointUniqueCode, Long pointId)
    {
        PatrolPoint existPoint = patrolPointMapper.checkPointCodeUnique(pointUniqueCode, pointId);
        if (existPoint != null)
        {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }
    
    /**
     * 根据二维码code查询点位信息
     * 
     * @param qrCode 二维码code
     * @return 点位信息
     */
    @Override
    public PatrolPoint selectPatrolPointByQrCode(String qrCode)
    {
        return patrolPointMapper.selectPatrolPointByQrCode(qrCode);
    }

    /**
     * 构建点位唯一编码
     * 规则：部门编码+楼栋+楼层+点位编码（中间不需要+）
     * @param patrolPoint
     * @param department
     * @return
     */
    private String buildPointUniqueCode(PatrolPoint patrolPoint, Department department) {
        if (patrolPoint == null || department == null) {
            return null;
        }
        
        if (StringUtils.isNotEmpty(department.getDeptCode())) {
            StringBuilder uniqueCode = new StringBuilder();
            uniqueCode.append(department.getDeptCode());
            
            // 添加建筑信息（如果存在）
            if (StringUtils.isNotEmpty(patrolPoint.getBuilding())) {
                uniqueCode.append(patrolPoint.getBuilding());
            }
            
            // 添加楼层信息（如果存在）
            if (StringUtils.isNotEmpty(patrolPoint.getFloor())) {
                uniqueCode.append(patrolPoint.getFloor());
            }
            
            // 添加点位编码（如果存在）
            if (StringUtils.isNotEmpty(patrolPoint.getPointCode())) {
                uniqueCode.append(patrolPoint.getPointCode());
            }
            
            return uniqueCode.toString();
        }
        return null;
    }

    /**
     * 批量导入点位信息
     *
     * @param patrolPointList 点位信息列表
     * @param updateSupport 是否更新支持，如果已存在，则进行更新数据
     * @param operName 操作用户
     * @return 结果
     */
    @Override
    @Transactional
    public String importPatrolPoint(List<PatrolPoint> patrolPointList, Boolean updateSupport, String operName)
    {
        if (StringUtils.isNull(patrolPointList) || patrolPointList.size() == 0)
        {
            throw new RuntimeException("导入点位数据不能为空！");
        }
        
        // 第一阶段：数据校验，收集所有错误信息
        int failureNum = 0;
        StringBuilder failureMsg = new StringBuilder();
        
        for (int i = 0; i < patrolPointList.size(); i++)
        {
            PatrolPoint patrolPoint = patrolPointList.get(i);
            try
            {
                // 数据验证
                String validationError = validatePatrolPointData(patrolPoint);
                if (StringUtils.isNotEmpty(validationError))
                {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、第" + (i + 1) + "行点位 " + patrolPoint.getPointCode() + " 校验失败：" + validationError);
                    continue;
                }
                
                // 先验证部门是否存在
                Department dept = null;
                if (StringUtils.isNotEmpty(patrolPoint.getDeptName()))
                {
                    dept = departmentMapper.selectDeptByName(patrolPoint.getDeptName());
                    if (dept == null)
                    {
                        failureNum++;
                        failureMsg.append("<br/>" + failureNum + "、第" + (i + 1) + "行点位 " + patrolPoint.getPointCode() + " 校验失败：" + patrolPoint.getDeptName() + "部门不存在，请先在部门管理中新增");
                        continue;
                    }
                    patrolPoint.setDeptId(dept.getDeptId());
                }
                
                // 生成点位唯一编码
                String pointUniqueCode = buildPointUniqueCode(patrolPoint, dept);
                if (StringUtils.isEmpty(pointUniqueCode))
                {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、第" + (i + 1) + "行点位 " + patrolPoint.getPointCode() + " 校验失败：无法生成点位唯一编码，请检查部门信息");
                    continue;
                }
                patrolPoint.setPointUniqueCode(pointUniqueCode);
                
                // 验证是否存在这个点位
                PatrolPoint p = null;
                PatrolPoint existPoint = patrolPointMapper.checkPointCodeUnique(pointUniqueCode, null);
                if (existPoint != null)
                {
                    p = patrolPointMapper.selectPatrolPointByPointId(existPoint.getPointId());
                }
                
                if (StringUtils.isNull(p))
                {
                    // 新增点位 - 验证安全员是否存在
                    
                    // 处理安全员信息
                    if (StringUtils.isNotEmpty(patrolPoint.getGuardName()) && StringUtils.isNotEmpty(patrolPoint.getGuardPhone()))
                    {
                        Long guardId = patrolPointMapper.selectGuardIdByNameAndPhone(patrolPoint.getGuardName(), patrolPoint.getGuardPhone());
                        if (guardId == null)
                        {
                            failureNum++;
                            failureMsg.append("<br/>" + failureNum + "、第" + (i + 1) + "行点位 " + patrolPoint.getPointCode() + " 校验失败：安全员 " + patrolPoint.getGuardName() + "(" + patrolPoint.getGuardPhone() + ") 不存在，请先在安全员管理中新增");
                            continue;
                        }
                    }
                }
                else if (!updateSupport)
                {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、第" + (i + 1) + "行点位 " + patrolPoint.getPointUniqueCode() + " 校验失败：已存在相同唯一编码的点位");
                    continue;
                }
                else
                {
                    // 更新点位 - 验证安全员是否存在
                    
                    // 处理安全员信息
                    if (StringUtils.isNotEmpty(patrolPoint.getGuardName()) && StringUtils.isNotEmpty(patrolPoint.getGuardPhone()))
                    {
                        Long guardId = patrolPointMapper.selectGuardIdByNameAndPhone(patrolPoint.getGuardName(), patrolPoint.getGuardPhone());
                        if (guardId == null)
                        {
                            failureNum++;
                            failureMsg.append("<br/>" + failureNum + "、第" + (i + 1) + "行点位 " + patrolPoint.getPointCode() + " 校验失败：安全员 " + patrolPoint.getGuardName() + "(" + patrolPoint.getGuardPhone() + ") 不存在，请先在安全员管理中新增");
                            continue;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                failureNum++;
                String msg = "<br/>" + failureNum + "、第" + (i + 1) + "行点位 " + patrolPoint.getPointCode() + " 校验失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        
        // 如果有校验失败的数据，直接返回错误信息，不执行任何导入操作
        if (failureNum > 0)
        {
            failureMsg.insert(0, "数据校验失败！共 " + failureNum + " 条数据不符合要求，请修正后重新导入。错误详情：");
            throw new RuntimeException(failureMsg.toString());
        }
        
        // 第二阶段：所有数据校验通过，执行导入操作
        int successNum = 0;
        int updateNum = 0;
        StringBuilder successMsg = new StringBuilder();
        
        for (PatrolPoint patrolPoint : patrolPointList)
        {
            try
            {
                // 处理部门名称转换为部门ID（如果还没有的话）
                Department dept = null;
                if (patrolPoint.getDeptId() == null && StringUtils.isNotEmpty(patrolPoint.getDeptName()))
                {
                    dept = departmentMapper.selectDeptByName(patrolPoint.getDeptName());
                    if (dept != null) {
                        patrolPoint.setDeptId(dept.getDeptId());
                    }
                }
                else if (patrolPoint.getDeptId() != null)
                {
                    dept = departmentMapper.selectDepartmentByDeptId(patrolPoint.getDeptId());
                }
                
                // 生成点位唯一编码（如果还没有的话）
                if (StringUtils.isEmpty(patrolPoint.getPointUniqueCode()))
                {
                    String pointUniqueCode = buildPointUniqueCode(patrolPoint, dept);
                    patrolPoint.setPointUniqueCode(pointUniqueCode);
                }
                
                // 验证是否存在这个点位
                PatrolPoint p = null;
                PatrolPoint existPoint = patrolPointMapper.checkPointCodeUnique(patrolPoint.getPointUniqueCode(), null);
                if (existPoint != null)
                {
                    p = patrolPointMapper.selectPatrolPointByPointId(existPoint.getPointId());
                }
                
                if (StringUtils.isNull(p))
                {
                    // 新增点位
                    patrolPoint.setCreateBy(operName);
                    patrolPoint.setCreateTime(DateUtils.getNowDate());
                    
                    // 处理安全员信息
                    if (StringUtils.isNotEmpty(patrolPoint.getGuardName()) && StringUtils.isNotEmpty(patrolPoint.getGuardPhone()))
                    {
                        Long guardId = patrolPointMapper.selectGuardIdByNameAndPhone(patrolPoint.getGuardName(), patrolPoint.getGuardPhone());
                        patrolPoint.setGuardId(guardId);
                        patrolPoint.setBindTime(DateUtils.getNowDate());
                    }
                    
                    this.insertPatrolPoint(patrolPoint, operName);
                    successNum++;
//                    successMsg.append("<br/>" + successNum + "、点位 " + patrolPoint.getPointCode() + " 导入成功");
                }
                else
                {
                    // 更新点位
                    patrolPoint.setPointId(p.getPointId());
                    patrolPoint.setUpdateBy(operName);
                    patrolPoint.setUpdateTime(DateUtils.getNowDate());
                    
                    // 处理安全员信息
                    if (StringUtils.isNotEmpty(patrolPoint.getGuardName()) && StringUtils.isNotEmpty(patrolPoint.getGuardPhone()))
                    {
                        Long guardId = patrolPointMapper.selectGuardIdByNameAndPhone(patrolPoint.getGuardName(), patrolPoint.getGuardPhone());
                        patrolPoint.setGuardId(guardId);
                    }
                    
                    this.updatePatrolPoint(patrolPoint, operName);
                    updateNum++;
//                    successMsg.append("<br/>" + (successNum + updateNum) + "、点位 " + patrolPoint.getPointCode() + " 更新成功");
                }
            }
            catch (Exception e)
            {
                // 理论上不会到这里，因为前面已经校验过了
                String msg = "点位 " + patrolPoint.getPointCode() + " 导入失败：" + e.getMessage();
                log.error(msg, e);
                throw new RuntimeException(msg);
            }
        }
        
        String resultMsg = "恭喜您，数据已全部导入成功！";
        if (successNum > 0 && updateNum > 0)
        {
            resultMsg += "共新增 " + successNum + " 条，更新 " + updateNum + " 条 ";
        }
        else if (successNum > 0)
        {
            resultMsg += "共新增 " + successNum + " 条 ";
        }
        else if (updateNum > 0)
        {
            resultMsg += "共更新 " + updateNum + " 条 ";
        }
        
        successMsg.insert(0, resultMsg);
        return successMsg.toString();
    }
    
    /**
     * 验证点位数据
     * 
     * @param patrolPoint 点位信息
     * @return 验证错误信息，为空表示验证通过
     */
    private String validatePatrolPointData(PatrolPoint patrolPoint)
    {
        // 验证必填字段
        if (StringUtils.isEmpty(patrolPoint.getPointCode()))
        {
            return "点位编码不能为空";
        }
        if (StringUtils.isEmpty(patrolPoint.getBuilding()))
        {
            return "楼栋不能为空";
        }
        if (StringUtils.isEmpty(patrolPoint.getFloor()))
        {
            return "楼层不能为空";
        }
        if (StringUtils.isEmpty(patrolPoint.getRoomNumber()))
        {
            return "房间号不能为空";
        }
        if (StringUtils.isEmpty(patrolPoint.getDeptName()))
        {
            return "所属部门名称不能为空";
        }
        if (StringUtils.isEmpty(patrolPoint.getGuardName()))
        {
            return "安全员名称不能为空";
        }
        if (StringUtils.isEmpty(patrolPoint.getGuardPhone()))
        {
            return "安全员手机号不能为空";
        }
        
        return null;
    }
    
    /**
     * 获取点位二维码base64
     * 
     * @param pointId 点位ID
     * @return 二维码base64字符串
     */
    @Override
    public String getQrCodeBase64(Long pointId)
    {
        try
        {
            PatrolPoint patrolPoint = patrolPointMapper.selectPatrolPointByPointId(pointId);
            if (patrolPoint == null)
            {
                return null;
            }
            
            // 如果已有base64缓存，直接返回
            if (StringUtils.isNotEmpty(patrolPoint.getQrCodeBase64()))
            {
                return patrolPoint.getQrCodeBase64();
            }
            
            // 生成二维码base64
            String qrContent = StringUtils.isNotEmpty(patrolPoint.getQrCode()) ? patrolPoint.getQrCode() : String.valueOf(pointId);
            String base64 = generateQRCodeBase64(qrContent);
            
            // 更新到数据库
            if (StringUtils.isNotEmpty(base64))
            {
                patrolPoint.setQrCodeBase64(base64);
                patrolPointMapper.updatePatrolPoint(patrolPoint);
            }
            
            return base64;
        }
        catch (Exception e)
        {
            log.error("获取点位二维码base64失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 批量下载二维码
     * 
     * @param patrolPointParam 点位查询
     * @param response HTTP响应
     */
    @Override
    public void batchDownloadQrCode(PatrolPoint patrolPointParam, HttpServletResponse response)
    {
        try
        {
            // 设置响应头
            response.setContentType("application/zip");
            response.setHeader("Content-Disposition", "attachment; filename=patrol_point_qrcodes.zip");
            
            try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream()))
            {
                List<PatrolPoint> patrolPointList = selectPatrolPointList(patrolPointParam);
                if (CollectionUtils.isNotEmpty(patrolPointList)) {
                    for (PatrolPoint patrolPoint : patrolPointList) {

                        if (patrolPoint != null)
                        {
                            // 生成二维码图片
                            String qrContent = StringUtils.isNotEmpty(patrolPoint.getQrCode()) ? patrolPoint.getQrCode() : String.valueOf(patrolPoint.getPointId());
                            byte[] qrCodeBytes = generateQRCodeBytes(qrContent);

                            if (qrCodeBytes != null)
                            {
                                // 添加到ZIP文件
                                String fileName = "点位_" + patrolPoint.getPointUniqueCode() + ".png";
                                ZipEntry zipEntry = new ZipEntry(fileName);
                                zos.putNextEntry(zipEntry);
                                zos.write(qrCodeBytes);
                                zos.closeEntry();
                            }
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
            log.error("批量下载二维码失败: {}", e.getMessage());
        }
    }
    
    /**
     * 生成二维码
     * 
     * @param pointId 点位ID
     * @return 二维码文件相对路径
     */
    private String generateQRCode(Long pointId)
    {
        try
        {
            // 二维码内容：点位ID
            String qrContent = String.valueOf(pointId);
            
            // 创建二维码目录
            String qrCodeDir = uploadPath + File.separator + "qrcode" + File.separator + "patrol";
            File dir = new File(qrCodeDir);
            if (!dir.exists())
            {
                dir.mkdirs();
            }
            
            // 生成文件名
            String fileName = "patrol_point_" + pointId + ".png";
            String filePath = qrCodeDir + File.separator + fileName;
            
            // 设置二维码参数
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.MARGIN, 1);
            
            // 生成二维码
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(qrContent, BarcodeFormat.QR_CODE, 200, 200, hints);
            
            // 保存二维码图片
            Path path = FileSystems.getDefault().getPath(filePath);
            MatrixToImageWriter.writeToPath(bitMatrix, "PNG", path);
            
            // 返回相对路径
            return "/qrcode/patrol/" + fileName;
        }
        catch (WriterException | IOException e)
        {
            log.error("生成二维码失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 生成二维码Base64字符串
     * 
     * @param content 二维码内容
     * @return Base64字符串
     */
    private String generateQRCodeBase64(String content)
    {
        try
        {
            // 设置二维码参数
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.MARGIN, 1);
            
            // 生成二维码
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 200, 200, hints);
            
            // 转换为BufferedImage
            BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
            
            // 转换为Base64
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "PNG", baos);
            byte[] imageBytes = baos.toByteArray();
            
            return Base64.getEncoder().encodeToString(imageBytes);
        }
        catch (Exception e)
        {
            log.error("生成二维码Base64失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 生成二维码字节数组
     * 
     * @param content 二维码内容
     * @return 字节数组
     */
    private byte[] generateQRCodeBytes(String content)
    {
        try
        {
            // 设置二维码参数
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            hints.put(EncodeHintType.MARGIN, 1);
            
            // 生成二维码
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, 200, 200, hints);
            
            // 转换为BufferedImage
            BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
            
            // 转换为字节数组
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "PNG", baos);
            
            return baos.toByteArray();
        }
        catch (Exception e)
        {
            log.error("生成二维码字节数组失败: {}", e.getMessage());
            return null;
        }
    }
}
